//#########################################################################
//                              WackiEngie
//           Copyright (c) 2014 Marc Wacker. All rights reserved.
//#########################################################################

#include "WeString.h"

namespace WackiEngine
{

	const String StringUtil::BLANK;
	const WString StringUtil::WBLANK;


	void StringUtil::trim(String& str, bool left, bool right)
	{
		static const String delims = " \t\r";
		trim(str, delims, left, right);
	}

	void StringUtil::trim(WString& str, bool left, bool right)
	{
		static const WString delims = L" \t\r";
		trim(str, delims, left, right);
	}

	void StringUtil::trim(String& str, const String& delims, bool left, bool right)
	{
		if(right)
			str.erase(str.find_last_not_of(delims) + 1); // trim right
		if(left)
			str.erase(0, str.find_first_not_of(delims)); // trim left
	}

	void StringUtil::trim(WString& str, const WString& delims, bool left, bool right)
	{
		if(right)
			str.erase(str.find_last_not_of(delims) + 1); // trim right
		if(left)
			str.erase(0, str.find_first_not_of(delims)); // trim left
	}

	Vector<String> StringUtil::split(const String& str, const String& delims, uint32 maxSplits)
	{
		return splitInternal<char>(str, delims, maxSplits);
	}

	Vector<WString> StringUtil::split(const WString& str, const WString& delims, uint32 maxSplits)
	{
		return splitInternal<wchar_t>(str, delims, maxSplits);
	}

	Vector<String> StringUtil::tokenize(const String& str, const String& delims, const String& doubleDelims, uint32 maxSplits)
	{
		return tokenizeInternal<char>(str, delims, doubleDelims, maxSplits);
	}

	Vector<WString> StringUtil::tokenize(const WString& str, const WString& delims, const WString& doubleDelims, uint32 maxSplits)
	{
		return tokenizeInternal<wchar_t>(str, delims, doubleDelims, maxSplits);
	}

	void StringUtil::toLowerCase(String& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), tolower);
	}

	void StringUtil::toLowerCase(WString& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), tolower);
	}

	void StringUtil::toUpperCase(String& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), toupper);
	}

	void StringUtil::toUpperCase(WString& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), toupper);
	}

	bool StringUtil::startsWith(const String& str, const String& pattern, bool caseSensitive)
	{
		return startsWithInternal<char>(str, pattern, caseSensitive);
	}

	bool StringUtil::startsWith(const WString& str, const WString& pattern, bool caseSensitive)
	{
		return startsWithInternal<wchar_t>(str, pattern, caseSensitive);
	}

	bool StringUtil::endsWith(const String& str, const String& pattern, bool caseSensitive)
	{
		return endsWithInternal<char>(str, pattern, caseSensitive);
	}

	bool StringUtil::endsWith(const WString& str, const WString& pattern, bool caseSensitive)
	{
		return endsWithInternal<wchar_t>(str, pattern, caseSensitive);
	}

	bool StringUtil::match(const String& str, const String& pattern, bool caseSensitive)
	{
		return matchInternal<char>(str, pattern, caseSensitive);
	}

	bool StringUtil::match(const WString& str, const WString& pattern, bool caseSensitive)
	{
		return matchInternal<wchar_t>(str, pattern, caseSensitive);
	}

	const String StringUtil::replaceAll(const String& source, const String& replaceWhat, const String& replaceWith)
	{
		return replaceAllInternal<char>(source, replaceWhat, replaceWith);
	}

	const WString StringUtil::replaceAll(const WString& source, const WString& replaceWhat, const WString& replaceWith)
	{
		return replaceAllInternal<wchar_t>(source, replaceWhat, replaceWith);
	}




	WString toWString(const String& source)
	{
		return WString(source.begin(), source.end());
	}

	WString toWString(float val, ushort precision,
		ushort width, char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.precision(precision);
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(double val, ushort precision,
		ushort width, char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.precision(precision);
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(int32 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(uint32 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(int64 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(uint64 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(char val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(wchar_t val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		WStringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	WString toWString(bool val, bool yesNo)
	{
		if(val)
		{
			if(yesNo)
				return L"yes";
			else
				return L"true";
		}
		else
		{
			if(yesNo)
				return L"no";
			else
				return L"false";
		}
	}



	String toString(const WString& source)
	{
		return String(source.begin(), source.end());
	}

	String toString(float val, ushort precision,
		ushort width, char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.precision(precision);
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(double val, ushort precision,
		ushort width, char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.precision(precision);
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(int32 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(uint32 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(int64 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(uint64 val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(char val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(wchar_t val, ushort width,
		char fill, std::ios::fmtflags flags)
	{
		StringStream stream;
		stream.width(width);
		stream.fill(fill);
		if(flags)
			stream.setf(flags);
		stream << val;
		return stream.str();
	}

	String toString(bool val, bool yesNo)
	{
		if(val)
		{
			if(yesNo)
				return "yes";
			else
				return "true";
		}
		else
		{
			if(yesNo)
				return "no";
			else
				return "false";
		}
	}



	//---------------------------------------
	//	STRING to TYPE conversions
	//---------------------------------------

	float parseFloat(const String& val, float defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		StringStream str(val);
		float ret = defaultValue;
		str >> ret;

		return ret;
	}

	int32 parseInt(const String& val, int32 defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		StringStream str(val);
		int32 ret = defaultValue;
		str >> ret;

		return ret;
	}

	uint32 parseUnsignedInt(const String& val, uint32 defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		StringStream str(val);
		uint32 ret = defaultValue;
		str >> ret;

		return ret;
	}

	long parseLong(const String& val, long defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		StringStream str(val);
		long ret = defaultValue;
		str >> ret;

		return ret;
	}

	unsigned long parseUnsignedLong(const String& val, unsigned long defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		StringStream str(val);
		unsigned long ret = defaultValue;
		str >> ret;

		return ret;
	}

	bool parseBool(const String& val, bool defaultValue)
	{
		if((StringUtil::startsWith(val, "true") || StringUtil::startsWith(val, "yes")
			|| StringUtil::startsWith(val, "1")))
			return true;
		else if((StringUtil::startsWith(val, "false") || StringUtil::startsWith(val, "no")
			|| StringUtil::startsWith(val, "0")))
			return false;
		else
			return defaultValue;
	}

	bool isNumber(const String& val)
	{
		StringStream str(val);
		float tst;
		str >> tst;
		return !str.fail() && str.eof();
	}



	float parseFloat(const WString& val, float defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		WStringStream str(val);
		float ret = defaultValue;
		str >> ret;

		return ret;
	}

	int32 parseInt(const WString& val, int32 defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		WStringStream str(val);
		int32 ret = defaultValue;
		str >> ret;

		return ret;
	}

	uint32 parseUnsignedInt(const WString& val, uint32 defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		WStringStream str(val);
		uint32 ret = defaultValue;
		str >> ret;

		return ret;
	}

	long parseLong(const WString& val, long defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		WStringStream str(val);
		long ret = defaultValue;
		str >> ret;

		return ret;
	}

	unsigned long parseUnsignedLong(const WString& val, unsigned long defaultValue)
	{
		// Use istringstream for direct correspondence with toString
		WStringStream str(val);
		unsigned long ret = defaultValue;
		str >> ret;

		return ret;
	}

	bool parseBool(const WString& val, bool defaultValue)
	{
		if((StringUtil::startsWith(val, L"true") || StringUtil::startsWith(val, L"yes")
			|| StringUtil::startsWith(val, L"1")))
			return true;
		else if((StringUtil::startsWith(val, L"false") || StringUtil::startsWith(val, L"no")
			|| StringUtil::startsWith(val, L"0")))
			return false;
		else
			return defaultValue;
	}

	bool isNumber(const WString& val)
	{
		WStringStream str(val);
		float tst;
		str >> tst;
		return !str.fail() && str.eof();
	}

}